package com.gitee.feizns.spring.validation.spring.boot.autoconfigure;

import com.gitee.feizns.quickstart.validation.ValidationUtils;
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;

import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

/**
 * 数据校验配置
 * @link <a href="https://blog.csdn.net/wangpengfei_p/article/details/122949239">SpringBoot Validation 快速失败(failFast)</a>
 * <p>
 *     该配置维持了数据校验的快速失败模式和支持自定义验证注解中注入spring bean<br/>
 *     快速失败模式是为了在数据校验过程中有一个失败即返回、而不进行多余的校验工作
 * </p>
 * <p>
 *     这里为了保证，在Spring对自动校验的配置能使用自己的Validator
 *     对自动配置的执行顺序进行了调整。保证当前类在 Spring Validation
 *     的自动配置类 ValidationAutoConfiguration 之前被初始化
 * </p>
 * @link <a href="https://blog.csdn.net/hanxiaotongtong/article/details/107196905">使用@AutoConfigureBefore、After、Order调整Spring Boot自动配置顺序</a>
 *
 * @see ValidationAutoConfiguration
 * @author feizns
 * @since 2022/09/12
 */
@Configuration
@AutoConfigureBefore(ValidationAutoConfiguration.class)
public class ValidatorAutoConfiguration {

    @Bean
    public Validator validator(AutowireCapableBeanFactory springFactory) {
        try (ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
                .configure()
                .failFast(true)
                // 解决 SpringBoot 依赖注入问题
                .constraintValidatorFactory(new SpringConstraintValidatorFactory(springFactory))
                .buildValidatorFactory()) {
            Validator validator = validatorFactory.getValidator();
            //配置到数据校验工具类中
            ValidationUtils.setValidator(validator);
            return validator;
        }
    }

}
